//
//  TempViewController.swift
//  WBDemo
//
//  Created by Jin on 25/04/2018.
//  Copyright © 2018 com.baidu.123. All rights reserved.
//

import UIKit

class TempViewController: UIViewController {
    
    //1.简单的json
    let json =
    """
     {
        "expires_in":157679999,
        "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
        "remind_in":"157679999",
        "isRealName":"true",
        "uid":"1763064413",
        "created_at":"2017-08-23T01:42:42Z",
        "duration":"NaN",
        "origin":"Ym94dWvpby5jb20=",
        "url":"www.baidu.com",
        "type":"free"
    }
    """
    //2.简单的嵌套json, list:字典数组
    let json_1 =
    """
    {
        "list":[
            {
                "expires_in":157679999,
                "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
                "remind_in":"157679999",
                "isRealName":"true",
                "uid":"1763064413",
                "created_at":"2017-08-23T01:42:42Z",
                "duration":"NaN",
                "origin":"Ym94dWvpby5jb20=",
                "url":"www.baidu.com",
                "type":"free"
            }
        ]
    }
    """
    
    //3.直接返回数组
    let json_2 =
    """
    [
        {
            "expires_in":157679999,
            "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
            "remind_in":"157679999",
            "isRealName":"true",
            "uid":"1763064413",
            "created_at":"2017-08-23T01:42:42Z",
            "duration":"NaN",
            "origin":"Ym94dWvpby5jb20=",
            "url":"www.baidu.com",
            "type":"free"
        }
    ]
    """
    
    //4.返回一个由key索引的数组
    let json_3 =
    """
    [
        {
            "episode":{
                "expires_in":157679999,
                "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
                "remind_in":"157679999",
                "isRealName":"true",
                "uid":"1763064413",
                "created_at":"2017-08-23T01:42:42Z",
                "duration":"NaN",
                "origin":"Ym94dWvpby5jb20=",
                "url":"www.baidu.com",
                "type":"free"
                }
        }
    ]
    """
    
     //5.返回一个更一般的json
    let json_4 =
    """
    {
        "meta":{
            "total_exp":1000,
            "level":"beginner",
            "total_duration":120
        },
        "list":[
            {
                "expires_in":157679999,
                "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
                "remind_in":"157679999",
                "isRealName":"true",
                "uid":"1763064413",
                "created_at":"2017-08-23T01:42:42Z",
                "duration":"NaN",
                "origin":"Ym94dWvpby5jb20=",
                "url":"www.baidu.com",
                "type":"free"
            }
        ]
    }
    """
    
    //6.自定义解码Json
    let json_5 =
        """
        {
            "expires_in":157679999,
            "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
            "remind_in":"157679999",
            "isRealName":"true",
            "uid":"1763064413",
            "created_at":"2017-08-23 00:00:00 CST",
            "duration":500.0,
            "origin":"Ym94dWvpby5jb20=",
            "url":"www.baidu.com",
            "type":"free",
            "comment":"null",
            "slices":[125,250,375]
        }
        """
    
    //7.自定义解码Json json与model不对应
    let json_6 =
    """
        {
            "expires_in":157679999,
            "access_token":"2.00nad_vBQlmNxBd37c5947315iTXAE",
            "remind_in":"157679999",
            "isRealName":"true",
            "uid":"1763064413",
            "created_at":"2017-08-23 00:00:00 CST",
            "origin":"Ym94dWvpby5jb20=",
            "url":"www.baidu.com",
            "type":"free",
            "comment":"null",
            "meta":{
                "duration":500.0,
                "slices":[125,250,375]
            }
        }
        """
    
    //8.api兼容
    let json_7_old =
    """
        {
            "created_at":"oct-21-2017"
        }
    """
    
    let json_7_new =
    """
        {
            "created_at":"2017-08-23T00:24:10+0800"
        }
    """
    
    //9.json中key个数不确定
    let json_8 =
    """
    {
        "1":{
            "title":"EpisodeKeys 1"
        },
        "2":{
            "title":"EpisodeKeys 2"
        },
        "3":{
            "title":"EpisodeKeys 3"
        },
        "4":{
            "title":"EpisodeKeys 4"
        }
    }
    """
    
    // MARK: - 视图生命周期
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.white
        
        let btn = UIButton()
        btn.setTitle("close", for: .normal)
        btn.frame = CGRect(x: 100, y: 200, width: 80, height: 40)
        btn.setTitleColor(UIColor.black, for: .normal)
        btn.backgroundColor = UIColor.orange
        btn.addTarget(self, action: #selector(closeBtnClick), for: .touchUpInside)
        btn.sizeToFit()
        view.addSubview(btn)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        //1.解析Json 简单的json
            //loadJson()
        //2.解析Json_1 嵌套list数组
            //loadJson_1()
        //3.解析Json_2 直接返回数组
            //loadJson_2()
        //4.解析Json_3 由key索引的数组
            //loadJson_3()
        //4.解析Json_4 一般json
            //loadJson_4()
        //5.自定义编码
            //encodeModel()
        //6.自定义解码
            //decodeJson()
        //7.自定义解码 json与model不对应
            //decodeJson_2()
        //8.派生类
            //test()
        //9.API兼容
            //testAPI(json: json_7_new)
        //10.json中key的个数不确定
            //testJson()
    }

    
    // MARK: - 内部控制方法
    @objc private func closeBtnClick(){
        dismiss(animated: true, completion: nil)
    }
    
    private func loadJson(){
        let decodeData = json.data(using: .utf8)!
        
        //解码 JSONDecoder Json -> Model
        let decoder = JSONDecoder()
        //对于日期时间的表达方式需要在编码和解码时做出处理,这是因为swift默认是使用时间间隔来表示时间的
        decoder.dateDecodingStrategy = .iso8601
        //对于浮点型,有时服务器会返回"NaN",这就需要处理一下
        //正无穷 负无穷 Not a Number
        decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
        //处理base64
        decoder.dataDecodingStrategy = .base64
        let userAccount = try? decoder.decode(Episode.self, from: decodeData)
        JLog(message: userAccount)
        
        //编码 JSONEncoder Model -> Json
        let encoder = JSONEncoder()
        //对于日期时间的表达方式需要在编码和解码时做出处理,这是因为swift默认是使用时间间隔来表示时间的
        encoder.dateEncodingStrategy = .iso8601
        //对于浮点型,有时服务器会返回"NaN",这就需要处理一下
        encoder.nonConformingFloatEncodingStrategy = .convertToString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
        //处理base64
        encoder.dataEncodingStrategy = .base64
        encoder.outputFormatting = .prettyPrinted
        let encodeData = try? encoder.encode(userAccount)
        let jsonStr = String(data: encodeData!, encoding: .utf8)
        JLog(message: jsonStr)
    }
    
    private func loadJson_1(){
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        decoder.dataDecodingStrategy = .base64
        decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
        
        let data = json_1.data(using: .utf8)!
        let list = try? decoder.decode(EpisodeList.self, from: data)
        JLog(message: list)
    }
    
    private func loadJson_2(){
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        decoder.dataDecodingStrategy = .base64
        decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
        
        let data = json_2.data(using: .utf8)!
        let list = try? decoder.decode([Episode].self, from: data)
        JLog(message: list)
    }
    
    private func loadJson_3(){
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        decoder.dataDecodingStrategy = .base64
        decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
        
        let data = json_3.data(using: .utf8)!
        let list = try? decoder.decode([Dictionary<String,Episode>].self, from: data)
        JLog(message: list)
    }
    
    private func loadJson_4(){
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        decoder.dataDecodingStrategy = .base64
        decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
        
        let data = json_4.data(using: .utf8)!
        let list = try? decoder.decode(EpisodePage.self, from: data)
        JLog(message: list)
    }
    
    private func encodeModel(){
        
        let episode = Episode(accessToken: "2.00nad_vBQlmNxBd37c5947315iTXAE",
                              expiresIn: 157679999,
                              remindIn: "157679999",
                              isRealName: "true",
                              uid: "1763064413",
                              type: .free,
                              createdAt: Date(),
                              duration: 6.5,
                              origin: Data(base64Encoded: "Ym94dWvpby5jb20=")!,
                              url: URL(string:"www.baidu.com")!,
                              comment: nil,
                              slices: [0.25,0.5,0.75])
        
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        //自定义日期编码处理
        encoder.dateEncodingStrategy = .custom({ (date, encoder) in
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
            let dateStr = formatter.string(from: date)
            //创建日期处理编码容器,由于只是处理一个日期,因此创建一个单值容器
            var container = encoder.singleValueContainer()
            try container.encode(dateStr)
            
        })
        let data = try? encoder.encode(episode)
        let jsonStr = String(data: data!, encoding: .utf8)
        JLog(message: jsonStr)
    }
    
    private func decodeJson(){
        let data = json_5.data(using: .utf8)!
        let decoder = JSONDecoder()
        //自定义日期解码处理
        decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
            let data = try decoder.singleValueContainer().decode(String.self)
            
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd HH:mm:sszzz"
            
            return formatter.date(from: data)!
        })
        let episode = try! decoder.decode(Episode.self, from: data)
        JLog(message: episode)
    }
    
    private func decodeJson_2(){
        let data = json_6.data(using: .utf8)!
        let decoder = JSONDecoder()
        
        //自定义日期解码处理
        decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
            let data = try decoder.singleValueContainer().decode(String.self)
            
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd HH:mm:sszzz"
            
            return formatter.date(from: data)!
        })
        let episode = try! decoder.decode(EpisodeGeneral.self, from: data)
        JLog(message: episode)
    }
    
    private func test(){
        let p1 = Point3D()
        p1.x = 1.0
        p1.y = 1.0
        p1.z = 1.0
        
        try? WBDemo.encode(of: p1, options: nil)
    }
    
    private func testAPI(json:String){
        let formatter = DateFormatter()
        //formatter.dateFormat = "MMM-dd-yyyy"
        formatter.dateFormat = "yyyy-MM-dd'T' HH:mm:ssz"
        
        let options = EpisodeCodingOptions(apiVersion: .v2, dateFormatter: formatter)
        
        let episode = EpisodeAPI(createdAt: Date())
        try? WBDemo.encode(of: episode, options: [EpisodeCodingOptions.infoKey:options])
    }
    
    private func testJson(){
        try? WBDemo.encode(of: decode(response: json_8, of: Episodes.self), options: [:])
    }
}
